package wili.b1.transform;

import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import wili.attrMapping._user.b1.AttConst;
import wili.attrMapping._user.b1.exp.AndOrExp2;
import wili.attrMapping._user.b1.exp.AndOrNode2;
import wili.attrMapping.file.JsonFile;
import wili.b1.FormulaTransform4b1;
import wili.b1.IncludesFun9;
import wili.b1.transform.Conf.Maping;
import wili.c.Ca;
import wili.c.Misc9a;
import wili.json.JsonLeaf;
import wili.json.JsonNode;
import wili.json.JsonObj;

/**
 * json file transform for b1.
 *
 * @author weila 2022年9月16日
 */
class JsonTransform4b1 implements AttConst {
	static final String EDITABLE = "editable", VISIBLE = "visible", FORMULA = "formula", UPDATABLE = "updatable";
	static final String FIND_LEAF = "".isEmpty() ? EDITABLE : FORMULA;
	JsonFile jsonFile;
	final JsonObj root;
	File toFile;

	public JsonTransform4b1(File fromFile, File toFile) {
		this(new JsonFile(fromFile), toFile);
	}

	public JsonTransform4b1(JsonFile fromFile, File toFile) {
		this.jsonFile = fromFile;
		this.root = this.jsonFile.root;
		this.toFile = toFile;
	}

	public JsonTransform4b1(String fromSt) {
		this.jsonFile = new JsonFile(fromSt);
		this.root = this.jsonFile.root;
	}

	public String transform() {
		this.config();
		String ret = jsonFile.refreshJsonSt();
		if ("asdfa".isEmpty())
			ret = new JsonTransform4b1_HBox(ret).transform();
		return ret;
	}

	public void config() {
		Ca.asert(false, "12-06");
		{
			List<JsonLeaf> fms;
			transform_to_includesFun(1);
			if ("".isEmpty())
				return;
		}
		{
			valueRegexpUpdate(1, "bind", "^\\w+$", "{$0}");
			attValueUpdate(1, "type", Maping.typeToCtrlType);
			nameUpdate_label_to_text(1);
			nameUpdate(1, "bind", "value", "type", "ctrlType");
			//
			{
				editableUpdate(1);
				visibleUpdate(1);
			}
			//
			attributeRemove(1, "columns", "grid");// change
		}
		{
			sortAttribute(-1, "", "uuid", "name");
			i18nUpdate(1);
		}
	}

	void i18nUpdate(int use) {
		if (use < 0)
			return;
	}

	void nameUpdate_label_to_text(int use) {
		if (use < 0)
			return;
		root.traverse(new Predicate<JsonNode>() {
			@Override
			public boolean test(JsonNode node) {
				if ("label".equals(node.attName)) {
					if (node.dad.valueOfSon(ctrlType, "").equals(HBox))
						return false;
					if (node.stringValue.isEmpty()) {
						node.dad.removeSon(node);
						return false;
					}
					JsonNode text = node.dad.son("text");
					if (text != null) {
						if (text.stringValue.isEmpty()) {
							text.setStringValue(node.stringValue);
							node.dad.removeSon(node);
							return false;
						}
						Ca.log(1, "\nWarn: both label and text:" + text);
						return false;
					}
					node.setAttName("text");
				}
				return false;
			}
		});
	}

	void nameUpdate(int use, String... kvList) {
		if (use < 0)
			return;
		root.traverse(new Predicate<JsonNode>() {
			@Override
			public boolean test(JsonNode node) {
				for (int i = 0; i < kvList.length; i += 2) {
					String nam = kvList[i];
					if (nam.equals(node.attName)) {
						node.setAttName(kvList[i + 1]);
						return false;
					}
				}
				return false;
			}
		});
	}

	void valueRegexpUpdate(int use, String leafName, String... kvList) {
		if (use < 0)
			return;
		List<JsonLeaf> leafs = root.findLeafs(leafName, null, -1);
		if (leafs == null)
			return;
		for (int i = 0; i < leafs.size(); i++) {
			JsonLeaf leaf = leafs.get(i);
			String value = leaf.stringValue;
			for (int j = 0; j < kvList.length; j += 2) {
				String newValue = value.replaceAll(kvList[j], kvList[j + 1]);
				if (!value.equals(newValue)) {
					leaf.setStringValue(newValue);
				}
			}
		}
	}

	void attValueUpdate(int use, String leafName, String... kvList) {
		if (use < 0)
			return;
		List<JsonLeaf> leafs = root.findLeafs(leafName, null, -1);
		if (leafs == null)
			return;
		Map<String, String> typeMap = Misc9a.mapOf(kvList);
		for (int i = 0; i < leafs.size(); i++) {
			JsonLeaf leaf = leafs.get(i);
			String value = leaf.stringValue;
			String toValue = typeMap.get(value);
			if (toValue == null) {
				Ca.log(1, "\n failed: updateLeafByValueMaping: " + value);
				continue;
			}
			if (toValue != null) {
				leaf.setStringValue(toValue);
			}
		}
	}

	void attributeRemove(int use, String... atts) {
		if (use < 0)
			return;
		List<String> attList = Arrays.asList(atts);
		List<JsonNode> list = root.findNodes(true, new Predicate<JsonNode>() {
			@Override
			public boolean test(JsonNode t) {
				if (attList.contains(t.attName))
					return true;
				return false;
			}
		});
		for (JsonNode at : list) {
			at.dad.removeSon(at);
		}
	}

	void sortAttribute(int use, String objName, String... orderList) {
		if (use < 0)
			return;
	}

	void editableUpdate(int use) {
		if (use < 0)
			return;
		Ca.asert(false, "12-08");
		/*
		 * "editable": { "defaultEditable": false, "defaultEditableOnGrid": false,
		 * "updatable": false, "permissionId": "0", "addModePermissionId": 0,
		 * "updateModePermissionId": 0, "editModePermissionId": 0 }
		 */
		//ConfigObjNodeValueMaping___.editableNode_to_leafValue(this.jsonFile);
		List<JsonNode> list = root.findNodesByName(false, EDITABLE);
		List<String> lis = list.stream().map(nd -> nd.dad.son("guid").stringValue).collect(Collectors.toList());
		if ("asdf".isEmpty())
			Ca.log(1, "editableUpdate, found guids:" + lis.size() + lis);
		for (int i = 0; i < list.size(); i++) {
			JsonNode nod = list.get(i);
			if (!(nod instanceof JsonObj))
				continue;
			JsonObj editable = (JsonObj) nod;
			Ca.log(-1, "editableUpdate, guid=", nod.dad.son("guid"));
			if (editable.mapingToValue__ != null) {
				editable.replaceBy(new JsonLeaf(EDITABLE, editable.mapingToValue__));
				continue;
			}
		}
	}

	List<JsonLeaf> formulaReplaceContent(int use, String... kvList) {
		if (use < 0)
			return null;
		List<JsonLeaf> fms = root.findLeafs(FIND_LEAF, null, -1);
		for (int i = 0; i < fms.size(); i++) {
			JsonLeaf fmLeaf = fms.get(i);
			String st = fmLeaf.stringValue;
			if (st.matches("\\w+"))
				continue;
			for (int j = 0; j < kvList.length; j += 2) {
				String key = kvList[j], va = kvList[j + 1];
				st = st.replaceAll(key, va);
			}
			// eg. "({ObjType} eq '13' or && {/DocType} eq 'I' or ${ObjType} eq '14') ~>...
			// st = st.replaceAll("\\{[\\/\\w]+\\}", "`$0").replace('`', '$').replace("$$",
			// "$");
			st = st.replaceAll("\\{[^\\{\\}]+\\}", "`$0").replace('`', '$').replace("$$", "$");
			st = st.trim();
			if (!st.startsWith("{=")) {
				st = "{=" + st + "}";
			}
			fmLeaf.setStringValue(st);
		}
		return fms;
	}

	void visibleUpdate(int use) {
		if (use < 0)
			return;
		/*
		 * "visible": { "defaultVisible": "true", "defaultVisibleOnGrid": true,
		 * "formula":
		 * "({VLawsSet} eq 'FR' or {VLawsSet} eq 'IT' or {VLawsSet} eq 'BE') and ({ObjType} eq '13' or {ObjType} eq '14' or {ObjType} eq '18' or {ObjType} eq '19')"
		 * , "permissionId": "0" }
		 */
		//ConfigObjNodeValueMaping___.visibleNode_to_leafValue(this.jsonFile);
		List<JsonNode> list = root.findNodesByName(true, VISIBLE);
		for (int i = 0; i < list.size(); i++) {
			JsonNode visiNode = list.get(i);
			if (!(visiNode instanceof JsonObj))
				continue;
			JsonObj visiObj = (JsonObj) visiNode;
			JsonLeaf leaf;
			String formulaSt = "true";
			if ((leaf = visiObj.son(FORMULA)) != null) {
				formulaSt = leaf.stringValue;
			} else if ((leaf = visiObj.son(UPDATABLE)) != null) {
				if (leaf.matchValue(true)) {
					formulaSt = "true";
				}
			} else {
			}
			visiNode.replaceBy(new JsonLeaf(VISIBLE, formulaSt));
		}
	}

	void transform_to_includesFun(int use) {
		if (use < 0)
			return;
		/*
		 * "formula":
		 * "({VLawsSet} eq 'FR' or {VLawsSet} eq 'IT' or {VLawsSet} eq 'BE') and ({ObjType} eq '13' or {ObjType} eq '14' or {ObjType} eq '18' or {ObjType} eq '19')"
		 * ,
		 */
		String st = FORMULA;
		st = EDITABLE;
		List<JsonLeaf> fms = root.findLeafs(st, null, -1);
		for (int i = 0; i < fms.size(); i++) {
			JsonLeaf fm = fms.get(i);
			String formulaSt = fm.stringValue;
			if (i == 20)
				Ca.pause();
			String ret;
			if ("".isEmpty()) {
				AndOrExp2 andOrExp = AndOrExp2.newInst(-1, formulaSt);
				AndOrNode2 nod = IncludesFun9.includesFun_transform(andOrExp.rootNode);
				ret = nod.getString(1);
			} else {
				ret = FormulaTransform4b1.transform___(formulaSt);
			}
			if (!ret.equals(formulaSt)) {
				fm.setStringValue(ret);
			}
		}
	}

	public static void main(String[] args) {
	}
}
